home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 January: Mac OS SDK / Dev.CD Jan 98 SDK2.toast / Development Kits (Disc 2) / QuickTime / Sample Code / QT Multiprocessor Support / recompress me.π / recompress me.c copy < prev    next >
Encoding:
Text File  |  1997-02-26  |  13.2 KB  |  413 lines  |  [TEXT/CWIE]

  1. #include <Devices.h>
  2. #include <Fonts.h>
  3. #include <ImageCompression.h>
  4. #include <Movies.h>
  5.  
  6. Boolean gDecompressingSourceFrame;
  7. Boolean gCompressingSourceFrame;
  8. Boolean gDecompressingToScreen;
  9.  
  10. pascal void decompressSrcFrameDone(OSErr result, short flags, long refcon);
  11. pascal void compressSrcFrameDone(OSErr result, short flags, long refcon);
  12. pascal void decompressToScreenDone(OSErr result, short flags, long refcon);
  13.  
  14. #define    MAX_SAMPLES    60
  15.  
  16. typedef struct {
  17.     long    duration;        // in milliseconds
  18.     long    size;            // sample size in bytes
  19. } SampleRecord;
  20.  
  21. typedef struct {
  22.     long    duration;
  23.     long    fileOffset;
  24.     long    dataSize;
  25.     Boolean isKeyFrame;
  26.     char    pad[3];
  27. } SampleEntryRecord, **SampleEntry;
  28.  
  29. void main(void)
  30. {
  31.     OSErr err;
  32.     StandardFileReply reply;
  33.     SFTypeList types;
  34.     Movie m;
  35.     short resFref;
  36.     WindowPtr w;
  37.     Rect bounds;
  38.     Track srcVideoTrack = nil;
  39.     Media srcVideoMedia;
  40.     Track dstVideoTrack = nil;
  41.     GWorldPtr gw[3];
  42.     ImageDescriptionHandle srcDesc = nil;
  43.     ImageSequence srcDecoSequences[3];
  44.     TimeValue timeNow;
  45.     TimeValue srcMovieDuration;
  46.     Handle srcVideoData1 = NewHandle(0);
  47.     Handle srcVideoData2 = NewHandle(0);
  48.     CodecFlags outFlags;
  49.     long srcVideoDataSize1, srcVideoDataSize2;
  50.     TimeValue mediaTimeNow;
  51.     Boolean useFirstBufferForCompress;
  52.     ICMCompletionProcRecord srcDecoCompletion, compressCompletion, screenDecoCompletion;
  53.     ImageDescriptionHandle compressedDesc = nil;
  54.     ImageSequence compSequence = 0;
  55.     long maxCompressionBufferSize;
  56.     Handle compressedData1 = nil, compressedData2 = nil;
  57.     long compressedDataSize1 = 0, compressedDataSize2 = 0;
  58.     UInt8 compressedSimilarity1, compressedSimilarity2;
  59.     ImageSequence screenDecoSequence = 0;
  60.     long i;
  61.     long currentCompressGWorldIndex;
  62.     long currentDecompressGWorldIndex;
  63.     DataRateParams dataRateStuff;
  64.     long sampleCount = 0;
  65.     SampleRecord sampleRecords[MAX_SAMPLES];
  66.     long totalDuration = 0, totalSize = 0;
  67.     SampleEntry theSampleRefs = (SampleEntry)NewHandle(0);
  68.     long currentFileOffset = 0;
  69.     short outputFref = 0;
  70.     IOParam    writeBlock;
  71.     short outputResRef = -1;
  72.     Movie newMovie = nil;
  73.  
  74.     Handle compressedFrameDurations = NewHandle(0);
  75.     Handle compressedFrameSize = NewHandle(0);
  76.  
  77.     InitGraf(&qd.thePort);
  78.     InitFonts();
  79.     InitWindows();
  80.     InitMenus();
  81.     TEInit();
  82.     InitDialogs(0L);
  83.     InitCursor();
  84.     MaxApplZone();
  85.  
  86.     EnterMovies();
  87.  
  88.     types[0] = MovieFileType;
  89.     StandardGetFilePreview(nil, 1, types, &reply);
  90.     if (!reply.sfGood) return;
  91.  
  92.     SetRect(&bounds, 75, 75, 75+160,75+120);
  93.     w = NewCWindow(nil, &bounds, reply.sfFile.name, false, 0, (WindowPtr)-1,
  94.         true, 0);
  95.     if (!w) return;
  96.  
  97.     SetPort(w);
  98.  
  99.     err = OpenMovieFile(&reply.sfFile, &resFref, fsRdPerm);
  100.     if (err) return;
  101.  
  102.     err = NewMovieFromFile(&m, resFref, nil, (StringPtr)nil,
  103.                 newMovieActive, nil);
  104.     if (err) return;
  105.  
  106.     CloseMovieFile(resFref);
  107.  
  108.     // create the output file
  109.     reply.sfFile.name[++reply.sfFile.name[0]] = '!';
  110.     err = CreateMovieFile(&reply.sfFile, 'TVOD', reply.sfScript, createMovieFileDeleteCurFile, &outputResRef, &newMovie);
  111.     if (err) return;
  112.  
  113.     err = FSpOpenDF(&reply.sfFile, fsRdWrPerm, &outputFref);
  114.     if (err) return;
  115.  
  116.     writeBlock.ioResult = 0;
  117.  
  118.     GetMovieBox(m, &bounds);
  119.     OffsetRect(&bounds, -bounds.left, -bounds.top);
  120.     SetMovieBox(m, &bounds);
  121.  
  122.     SizeWindow(w, bounds.right, bounds.bottom, false);
  123.     ShowWindow(w);
  124.  
  125.     for (i=0; i<3; i++) {
  126.         err = NewGWorld(&gw[i], 32, &bounds, nil, nil, 0);
  127.         if (err) {
  128.             err = NewGWorld(&gw[i], 32, &bounds, nil, nil, useTempMem);
  129.             if (err) return;
  130.         }
  131.         LockPixels(gw[i]->portPixMap);
  132.     }
  133.  
  134.     srcVideoTrack = GetMovieIndTrackType(m, 1, 'vide', movieTrackEnabledOnly | movieTrackMediaType);
  135.     if (!srcVideoTrack) return;
  136.  
  137.     srcVideoMedia = GetTrackMedia(srcVideoTrack);
  138.     srcDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  139.     if (!srcDesc) return;
  140.     GetMediaSampleDescription(srcVideoMedia, 1, (SampleDescriptionHandle)srcDesc);
  141.  
  142.     for (i=0; i<3; i++) {
  143.         err = DecompressSequenceBegin(&srcDecoSequences[i], srcDesc, gw[i], nil, nil, nil, ditherCopy, nil, 0, codecNormalQuality, anyCodec);
  144.         if (err) return;
  145.     }
  146.  
  147.     srcDecoCompletion.completionProc = NewICMCompletionProc(decompressSrcFrameDone);
  148.     srcDecoCompletion.completionRefCon = (long)&gDecompressingSourceFrame;
  149.     gDecompressingSourceFrame = false;
  150.  
  151.     compressCompletion.completionProc = NewICMCompletionProc(compressSrcFrameDone);
  152.     compressCompletion.completionRefCon = (long)&gCompressingSourceFrame;
  153.     gCompressingSourceFrame = false;
  154.  
  155.     screenDecoCompletion.completionProc = NewICMCompletionProc(decompressToScreenDone);
  156.     screenDecoCompletion.completionRefCon = (long)&gDecompressingToScreen;
  157.     gDecompressingToScreen = false;
  158.  
  159.     compressedDesc = (ImageDescriptionHandle)NewHandle(0);
  160.     if (!compressedDesc) return;
  161.  
  162.     err = CompressSequenceBegin(&compSequence, gw[0]->portPixMap, nil, nil, nil, 24, 'cvid', anyCodec, codecLosslessQuality - 1, codecLosslessQuality - 1, 15, nil, nil, compressedDesc);
  163.     if (err) return;
  164.  
  165.     err = GetMaxCompressionSize(gw[0]->portPixMap, &gw[0]->portRect, 24, codecLosslessQuality - 1, 'cvid', anyCodec, &maxCompressionBufferSize);
  166.     if (err) return;
  167.  
  168.     compressedData1 = NewHandle(maxCompressionBufferSize);
  169.     compressedData2 = NewHandle(maxCompressionBufferSize);
  170.     if (!compressedData1 || !compressedData2)
  171.         return;
  172.  
  173.     HLockHi(compressedData1);
  174.     HLockHi(compressedData2);
  175.  
  176.     dataRateStuff.dataRate = 240 * 1024;
  177.     dataRateStuff.keyFrameRate = 30;
  178.     dataRateStuff.minSpatialQuality = codecLosslessQuality - 1;
  179.     dataRateStuff.minTemporalQuality = codecLosslessQuality - 1;
  180.     totalDuration = 1000;
  181.     totalSize = dataRateStuff.dataRate;
  182.     sampleRecords[0].size = dataRateStuff.dataRate;
  183.     sampleRecords[0].duration = 1000;
  184.     sampleCount = 1;
  185.  
  186.     srcMovieDuration = GetMovieDuration(m);
  187.     timeNow = 0;
  188.  
  189.     // prime the loop by decompressing the first frame into the first gworld
  190.     mediaTimeNow = TrackTimeToMediaTime(timeNow, srcVideoTrack);
  191.     if (mediaTimeNow == -1) return;
  192.  
  193.     err = GetMediaSample(srcVideoMedia, srcVideoData1, 0, &srcVideoDataSize1, mediaTimeNow, nil, nil, nil, nil, 1, nil, nil);
  194.     if (err) return;
  195.  
  196.     HLock(srcVideoData1);
  197.     err = DecompressSequenceFrameS(srcDecoSequences[0], *srcVideoData1, srcVideoDataSize1, 0, &outFlags, nil);
  198.     if (err) return;
  199.  
  200.     HUnlock(srcVideoData1);
  201.  
  202.     // figure out the next frame time
  203.     GetTrackNextInterestingTime(srcVideoTrack, nextTimeMediaSample | nextTimeIgnoreActiveSegment, timeNow, 1, &timeNow, nil);
  204.     if (timeNow == -1) return;
  205.  
  206.     // load the next frame to decompress
  207.     mediaTimeNow = TrackTimeToMediaTime(timeNow, srcVideoTrack);
  208.     if (mediaTimeNow == -1) return;
  209.  
  210.     err = GetMediaSample(srcVideoMedia, srcVideoData1, 0, &srcVideoDataSize1, mediaTimeNow, nil, nil, nil, nil, 1, nil, nil);
  211.     if (err) return;
  212.  
  213.     // initialize more stuff
  214.     useFirstBufferForCompress = true;
  215.     currentCompressGWorldIndex = 0;
  216.     currentDecompressGWorldIndex = 1;
  217.  
  218.     while (timeNow < srcMovieDuration) {
  219.         TimeValue mediaTimeNow = TrackTimeToMediaTime(timeNow, srcVideoTrack);
  220.  
  221.         if (Button())
  222.             break;
  223.  
  224.         if (mediaTimeNow != -1) {
  225.             // wait for last source frame to finish decompressing
  226.             while (gDecompressingSourceFrame)
  227.                 ;
  228.  
  229.             // start that next source frame decompressing
  230.             gDecompressingSourceFrame = true;
  231.             HLock(useFirstBufferForCompress ? srcVideoData1 : srcVideoData2);
  232.             err = DecompressSequenceFrameS(srcDecoSequences[currentDecompressGWorldIndex],
  233.                         useFirstBufferForCompress ? *srcVideoData1 : *srcVideoData2,
  234.                         useFirstBufferForCompress ? srcVideoDataSize1 : srcVideoDataSize2, 0, &outFlags, &srcDecoCompletion);
  235.             if (err) return;
  236.  
  237.             // read next source frame
  238.             HUnlock(useFirstBufferForCompress ? srcVideoData2 : srcVideoData1);
  239.             err = GetMediaSample(srcVideoMedia, useFirstBufferForCompress ? srcVideoData2 : srcVideoData1,
  240.                         0, useFirstBufferForCompress ? &srcVideoDataSize2 : &srcVideoDataSize1, mediaTimeNow, nil, nil, nil, nil, 1, nil, nil);
  241.             if (err) return;
  242.  
  243.             // wait for last compress to finish compressing
  244.             while (gCompressingSourceFrame)
  245.                 ;
  246.  
  247.             // figure out the data rate parameters for this next frame
  248.             if (sampleCount < MAX_SAMPLES) {
  249.                 SampleRecord *srp = &sampleRecords[sampleCount];
  250.                 srp->duration = 33;        //•• evil
  251.                 srp->size = useFirstBufferForCompress ? compressedDataSize2 : compressedDataSize1;
  252.                 totalDuration += 33;    //•• evil
  253.                 totalSize += srp->size;
  254.                 sampleCount++;
  255.             }
  256.  
  257.             // drop (totalDuration - 1000) worth of sample data
  258.             {
  259.                 long n = totalDuration - 1000;
  260.                 while (n && totalDuration && sampleCount) {
  261.                     if (n - sampleRecords[0].duration >= 0) {
  262.                         short i;
  263.                         n -= sampleRecords[0].duration;
  264.                         totalDuration -= sampleRecords[0].duration;
  265.                         totalSize -= sampleRecords[0].size;
  266.                         for (i = 1; i < sampleCount; i++)
  267.                             sampleRecords[i-1] = sampleRecords[i];
  268.                         sampleCount--;
  269.                     } else {
  270.                         long dec = n * sampleRecords[0].size / sampleRecords[0].duration;
  271.                         sampleRecords[0].size -= dec;
  272.                         sampleRecords[0].duration -= n;
  273.                         totalSize -= dec;
  274.                         totalDuration -= n;
  275.                         n = 0;
  276.                     }
  277.                 }
  278.             }
  279.  
  280.             dataRateStuff.dataOverrun = totalSize - dataRateStuff.dataRate;
  281.             dataRateStuff.frameDuration = 33;        //•• evil
  282.             SetCSequenceDataRateParams(compSequence, &dataRateStuff);
  283.  
  284.             if (screenDecoSequence) {
  285.                 // write out to disk the most recently compressed frame
  286.                 SampleEntryRecord ser;
  287.  
  288.                 ser.duration = 33;                //•• evil
  289.                 ser.fileOffset = currentFileOffset;
  290.                 ser.dataSize = useFirstBufferForCompress ? compressedDataSize2 : compressedDataSize1;
  291.                 ser.isKeyFrame = (useFirstBufferForCompress ? compressedSimilarity2 : compressedSimilarity1) == 0;
  292.                 err = PtrAndHand(&ser, (Handle)theSampleRefs, sizeof(ser));
  293.                 if (err) break;
  294.  
  295.                 // wait for previous write to complete
  296.                 while (writeBlock.ioResult == 1)
  297.                     ;
  298.  
  299.                 if (writeBlock.ioResult != noErr) return;
  300.  
  301.                 writeBlock.ioRefNum = outputFref;
  302.                 writeBlock.ioPosMode = fsFromStart;
  303.                 writeBlock.ioPosOffset = currentFileOffset;
  304.                 writeBlock.ioReqCount = ser.dataSize;
  305.                 writeBlock.ioBuffer = useFirstBufferForCompress ? *compressedData2 : *compressedData1;
  306.                 writeBlock.ioCompletion = nil;
  307.  
  308.                 PBWriteAsync((ParmBlkPtr)&writeBlock);
  309.  
  310.                 currentFileOffset += ser.dataSize;
  311.             }
  312.  
  313.             // compress last source frame
  314.             err = SetCSequencePrev(compSequence, gw[(currentCompressGWorldIndex + 2) % 3]->portPixMap, &gw[0]->portRect);
  315.             if (err) return;
  316.  
  317.             err = CompressSequenceFrame(compSequence, gw[currentCompressGWorldIndex]->portPixMap,
  318.                         nil, 0, useFirstBufferForCompress ? *compressedData1 : *compressedData2,
  319.                         useFirstBufferForCompress ? &compressedDataSize1 : &compressedDataSize2,
  320.                         useFirstBufferForCompress ? &compressedSimilarity1 : &compressedSimilarity2,
  321.                         &compressCompletion);
  322.             if (err) return;
  323.  
  324.             // wait for decompress to screen frame to finish decompressing
  325.             while (gDecompressingToScreen)
  326.                 ;
  327.  
  328.             // probably decompress the last compressed frame to the screen
  329.             if (!screenDecoSequence) {
  330.                 // first time around, just make up the decompress sequence
  331.                 err = DecompressSequenceBegin(&screenDecoSequence, compressedDesc, (CGrafPtr)w, nil, nil, nil, ditherCopy, nil, 0, codecNormalQuality, anyCodec);
  332.                 if (err) return;
  333.             }
  334.             else {
  335.                 // all other times, decompress last compressed frame to screen
  336.                 gDecompressingToScreen = true;
  337.                 err = DecompressSequenceFrameS(screenDecoSequence,
  338.                             useFirstBufferForCompress ? *compressedData2 : *compressedData1,
  339.                             useFirstBufferForCompress ? compressedDataSize2 : compressedDataSize1, 0, &outFlags, &screenDecoCompletion);
  340.                 if (err) return;
  341.             }
  342.  
  343.             useFirstBufferForCompress = !useFirstBufferForCompress;
  344.             currentCompressGWorldIndex = (currentCompressGWorldIndex + 1) % 3;
  345.             currentDecompressGWorldIndex = (currentDecompressGWorldIndex + 1) % 3;
  346.         }
  347.  
  348.         GetTrackNextInterestingTime(srcVideoTrack, nextTimeMediaSample | nextTimeIgnoreActiveSegment, timeNow, 1, &timeNow, nil);
  349.         if (timeNow == -1)
  350.             timeNow = srcMovieDuration;
  351.     }
  352.  
  353.     {
  354.     long sampleCount = GetHandleSize((Handle)theSampleRefs) / sizeof(SampleEntryRecord);
  355.     long i;
  356.     Track dstVideoTrack;
  357.     Media dstVideoMedia;
  358.  
  359.     dstVideoTrack = NewMovieTrack(newMovie, (**compressedDesc).width << 16, (**compressedDesc).height << 16, 0);
  360.     dstVideoMedia = NewTrackMedia(dstVideoTrack, 'vide', 1000, nil, 0);
  361.  
  362.     for (i=0; i<sampleCount; i++) {
  363.         SampleEntryRecord ser = (*theSampleRefs)[i];
  364.  
  365.         err = AddMediaSampleReference(dstVideoMedia, ser.fileOffset, ser.dataSize, ser.duration, (SampleDescriptionHandle)compressedDesc,
  366.                 1, ser.isKeyFrame ? 0 : mediaSampleNotSync, nil);
  367.         if (err) return;
  368.     }
  369.  
  370.     err = InsertMediaIntoTrack(dstVideoTrack, 0, 0, GetMediaDuration(dstVideoMedia), 1 << 16);
  371.     if (err) return;
  372.  
  373.     err = AddMovieResource(newMovie, outputResRef, nil, nil);
  374.     if (err) return;
  375.     }
  376.  
  377. bail:
  378.     CDSequenceEnd(screenDecoSequence);
  379.  
  380.     for (i=0; i<3; i++)
  381.         CDSequenceEnd(srcDecoSequences[i]);
  382.  
  383.     CDSequenceEnd(compSequence);
  384.  
  385.     if (outputFref) FSClose(outputFref);
  386.     if (outputResRef != -1) CloseMovieFile(outputResRef);
  387.  
  388.     if (newMovie) DisposeMovie(newMovie);
  389. }
  390.  
  391. pascal void decompressSrcFrameDone(OSErr /* result */, short flags, long refcon)
  392. {
  393.     Boolean *decompressingFlag = (Boolean *)refcon;
  394.  
  395.     if (flags & codecCompletionDest)
  396.         *decompressingFlag = false;
  397. }
  398.  
  399. pascal void compressSrcFrameDone(OSErr /* result */, short flags, long refcon)
  400. {
  401.     Boolean *compressingFlag = (Boolean *)refcon;
  402.  
  403.     if (flags & codecCompletionDest)
  404.         *compressingFlag = false;
  405. }
  406.  
  407. pascal void decompressToScreenDone(OSErr /* result */, short flags, long refcon)
  408. {
  409.     Boolean *decompressingFlag = (Boolean *)refcon;
  410.     if (flags & codecCompletionDest)
  411.         *decompressingFlag = false;
  412. }
  413.